﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

namespace Streambolics.Hp41s
{
    /// <summary>
    ///     A catalog of useable functions.
    /// </summary>

    public class Catalog
    {
        private Dictionary<string, InstructionFactory> _Instructions = new Dictionary<string, InstructionFactory> ();

        public Catalog ()
        {
            AddLibrary (typeof (CommonInstructions));
        }

        public InstructionFactory GetFactory (string aName)
        {
            if (_Instructions.ContainsKey (aName))
            {
                return _Instructions[aName];
            }
            else
            {
                return null;
            }
        }

        public void AddInstruction (InstructionFactory aFactory)
        {
            _Instructions.Add (aFactory.Name, aFactory);
        }

        [Obsolete]
        public void AddReadyMadeInstruction (string aName, Instruction aInstruction)
        {
            AddInstruction (new ReadyMadeInstructionFactory (aName, aInstruction));
        }

        [Obsolete]
        public void AddReferenceInstruction (string aName, MethodInfo aFactory)
        {
            AddInstruction (new ReferenceInstructionFactory (aName, aFactory));
        }

        [Obsolete]
        public void AddRefOrStringInstruction (string aName, MethodInfo aFactory)
        {
            AddInstruction (new RefOrStringInstructionFactory (aName, aFactory));
        }

        public void AddLibraryMember (MemberInfo aMember)
        {
            foreach (object attribute in aMember.GetCustomAttributes (true))
            {
                if (attribute is InstructionAttribute)
                {
                    ((InstructionAttribute)attribute).Register (aMember, this);
                }
            }
        }

        /// <summary>
        ///     Adds a library of instructions to the catalog
        /// </summary>
        /// <param name="aLibraryClass">
        ///     The type of the class implementing the instructions.
        /// </param>
        /// <remarks><para>
        ///     The type must represent a static class exposing public fields
        ///     and methods representing the instructions to add to the
        ///     library.
        /// </para><para>
        ///     Members of the type, decorated with attributes deriving from
        ///     InstructionAttribute (eg SimpleInstructionAttribute, ReferenceInstructionAttribute)
        ///     are added to the compiler as callable methods.
        /// </para></remarks>

        public void AddLibrary (Type aLibraryClass)
        {
            foreach (var f in aLibraryClass.GetFields ())
            {
                AddLibraryMember (f);
            }

            foreach (var m in aLibraryClass.GetMethods ())
            {
                AddLibraryMember (m);
            }
        }
    }
}
